package com.sinosoft.hydra.um.services;

import com.sinosoft.hydra.um.condition.SearchUserCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.model.DataItem;
import com.sinosoft.hydra.um.domain.permission.*;
import cn.com.sinux.spring.exception.BusinessException;
import com.sinosoft.hydra.um.helper.AuthContextHelper;
import com.sinosoft.hydra.um.repositories.*;
import com.sinosoft.hydra.um.utils.AppUtils;
import cn.com.sinux.spring.utils.PageUtils;
import cn.com.sinux.spring.utils.SpecificationHelper;
import cn.com.sinux.spring.utils.ValidatorUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.*;

/**
 * @author liangminga
 * @since 0.5-alpha
 * 2014年12月17日
 * 描述：进行用户的增删查改等操作。验证增加用户时用户名称重复，编辑用户时用户名称重复的功能。
 */
@Service
public class SysUserService {
    /**
     * 用户持久化类
     */
    @Autowired
    private SysUserRepository sysUserRepository;
    /**
     * 加密设置持久化类
     */
    @Autowired
    private SysUserSecurityTypeService sysUserSecurityTypeService;

    @Autowired
    private SysOrganizationRepository sysOrganizationRepository;
    /**
     * 角色数据层
     */
    @Autowired
    private SysRoleRepository sysRoleRepository;

    @Autowired
    private TAttendanceDAO attendanceDAO;

    @Autowired
    private SysOrganizationUserRepository orgUserRepository;

    /**
     * 修改用户时重复用户员工号验证
     *
     * @param userNumber 用户员工号
     * @param id         用户主键
     * @return 布尔值 true:相同 false:不同
     */
    public boolean repeatValidate(final String userNumber, final String id) {
        return sysUserRepository.count(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {

            public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("userNumber").as(String.class), StringUtils.trim(userNumber)));
                if (StringUtils.isNotBlank(id)) {
                    list.add(cb.notEqual(root.get("id").as(String.class), id));
                }
            }
        })) > 0;
    }

    public String ipRepeat(String ipAddress, final String id){
        List<String> repeat = new ArrayList<String>();
        for (final String ip : StringUtils.split(ipAddress, ",")) {
            List<SysUserMember> users = sysUserRepository.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {

                public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
//                    list.add(cb.like(root.get("ipAddress").as(String.class), "%" + StringUtils.trim(ip) + "%"));
                    list.add(cb.equal(root.get("ipAddress").as(String.class), StringUtils.trim(ip)));
                    if (StringUtils.isNotBlank(id)){
                        list.add(cb.notEqual(root.get("id").as(String.class), id));
                    }
                }
            }));
            if (users.size() > 0){
                repeat.add(ip);
            }
        }
        return StringUtils.join(repeat, ",");
    }

    /**
     * 角色用户树
     *
     * @param roleId 角色id
     * @return List<TreeNode> 节点列表
     */
    public List<DataItem> roleUsers(String roleId) {
        List<DataItem> results = new ArrayList<DataItem>();
        List<SysUserMember> li = sysUserRepository.findAll();
        SysRole role = sysRoleRepository.findOne(roleId);
        List<String> selected = new ArrayList<String>();
        if (role != null && ValidatorUtils.isArrayNotEmpty(role.getSysUserMembers())) {
            for (SysUserMember sysUserMember : role.getSysUserMembers()) {
                selected.add(sysUserMember.getId());
            }
        }
        for (SysUserMember user : li) {
            DataItem item = new DataItem();
            item.setId(user.getId());
            item.setName(user.getUserName());
            if (selected.contains(user.getId())) {
                item.setChecked(true);
            }
            results.add(item);
        }
        return results;
    }

    /**
     * 新增用户
     *
     * @param userMember 用户
     * @return 成功或失败数据
     */
    public SysUserMember addSysUser(SysUserMember userMember) {
        if (repeatValidate(userMember.getUserNumber(), null)) {
            throw new BusinessException("yong.hu.yuan.gong.hao.yi.jing.cun.zai");
        }
        if (StringUtils.isNotBlank(userMember.getIpAddress())){
            String repeatIp = ipRepeat(userMember.getIpAddress(), null);
            if (StringUtils.isNotBlank(repeatIp)){
                throw new BusinessException("IP地址{" + repeatIp + "}已存在");
            }
        }
        SysUserSecurityType sysUserSecurityType = sysUserSecurityTypeService.getSysUserSecurityType();
        if (sysUserSecurityType != null) {
            if (BaseConstant.MD5.equals(sysUserSecurityType.getSecurityType())) {//32
                userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "MD5"));
            } else if (BaseConstant.SHA_1.equals(sysUserSecurityType.getSecurityType())) {//40
                userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "SHA-1"));
            } else if (BaseConstant.SHA_256.equals(sysUserSecurityType.getSecurityType())) {//64
                userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "SHA-256"));
            }
        } else {
            userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "MD5"));
        }
        sysUserRepository.save(userMember);
        return userMember;
    }

    /**
     * 修改用户
     *
     * @param userMember 用户
     * @return 哈希对象
     */
    public SysUserMember updateSysUser(SysUserMember userMember) {
        SysUserMember sysUserMember = sysUserRepository.findOne(userMember.getId());
        if (repeatValidate(userMember.getUserNumber(), userMember.getId())) {
            throw new BusinessException("yong.hu.yuan.gong.hao.yi.jing.cun.zai.geng.xin.shi.bai");
        }
        if (StringUtils.isNotBlank(userMember.getIpAddress())){
            String repeatIp = ipRepeat(userMember.getIpAddress(), userMember.getId());
            if (StringUtils.isNotBlank(repeatIp)){
                throw new BusinessException("IP地址{" + repeatIp + "}已存在,更新失败");
            }
        }
        userMember.setCreateTime(sysUserMember.getCreateTime());
        userMember.setSysRoles(sysUserMember.getSysRoles());
        userMember.setSysOrganizationUsers(sysUserMember.getSysOrganizationUsers());
        SysUserSecurityType sysUserSecurityType = sysUserSecurityTypeService.getSysUserSecurityType();
        if (!userMember.getUserPassword().equals(sysUserMember.getUserPassword())) {
            String userSalt = userMember.getUserSalt();
            userSalt = StringUtils.isNotBlank(userSalt) ? userSalt : sysUserMember.getUserSalt();
            if (sysUserSecurityType != null) {
                if (BaseConstant.MD5.equals(sysUserSecurityType.getSecurityType())) {//32
                    userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "MD5"));
                } else if (BaseConstant.SHA_1.equals(sysUserSecurityType.getSecurityType())) {//40
                    userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "SHA-1"));
                } else if (BaseConstant.SHA_256.equals(sysUserSecurityType.getSecurityType())) {//64
                    userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "SHA-256"));
                }
            } else {
                userMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "MD5"));
            }
        } else {
            userMember.setUserSalt(sysUserMember.getUserSalt());
        }
        sysUserRepository.save(userMember);
        return userMember;
    }

    /**
     * 修改用户
     *
     * @param userMember 用户
     * @return 哈希对象
     */
    public SysUserMember changeUserInfo(SysUserMember userMember) {
        SysUserMember sysUserMember = sysUserRepository.findOne(userMember.getId());
        if (repeatValidate(userMember.getUserNumber(), userMember.getId())) {
            throw new BusinessException("yong.hu.yuan.gong.hao.yi.jing.cun.zai.geng.xin.shi.bai");
        }
        if (StringUtils.isNotBlank(userMember.getIpAddress())){
            String repeatIp = ipRepeat(userMember.getIpAddress(), userMember.getId());
            if (StringUtils.isNotBlank(repeatIp)){
                throw new BusinessException("IP地址{" + repeatIp + "}已存在,更新失败");
            }
        }
        sysUserMember.setUserNumber(userMember.getUserNumber());
        sysUserMember.setUserName(userMember.getUserName());
        sysUserMember.setUserHead(userMember.getUserHead());
        sysUserMember.setEmail(userMember.getEmail());
        sysUserMember.setMobile(userMember.getMobile());
        sysUserMember.setIpAddress(userMember.getIpAddress());
        SysUserSecurityType sysUserSecurityType = sysUserSecurityTypeService.getSysUserSecurityType();
        if (!userMember.getUserPassword().equals(sysUserMember.getUserPassword())) {
            String userSalt = userMember.getUserSalt();
            userSalt = StringUtils.isNotBlank(userSalt) ? userSalt : sysUserMember.getUserSalt();
            if (sysUserSecurityType != null) {
                if (BaseConstant.MD5.equals(sysUserSecurityType.getSecurityType())) {//32
                    sysUserMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "MD5"));
                } else if (BaseConstant.SHA_1.equals(sysUserSecurityType.getSecurityType())) {//40
                    sysUserMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "SHA-1"));
                } else if (BaseConstant.SHA_256.equals(sysUserSecurityType.getSecurityType())) {//64
                    sysUserMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userSalt, 32, "SHA-256"));
                }
            } else {
                sysUserMember.setUserPassword(AppUtils.GetMD5(userMember.getUserPassword() + userMember.getUserSalt(), 32, "MD5"));
            }
        }
        sysUserRepository.save(sysUserMember);
        return sysUserMember;
    }

    /**
     * 启用用户
     *
     * @param ids 用户主键集
     * @return 成功或失败数据
     */
    @Transactional
    public List<SysUserMember> changeUserStatus(List<String> ids, Integer status) {
        if (BaseConstant.INTEGER_TRUE.equals(status)) {
            sysUserRepository.disabled(ids);
        } else {
            sysUserRepository.enable(ids);
        }
        return sysUserRepository.findAll(ids);
    }

    /**
     * 根据主键查找某一个用户
     *
     * @param id 用户主键
     * @return SysUserMember 用户
     */
    public SysUserMember findOne(String id) {
        return StringUtils.isBlank(id) ? null : sysUserRepository.findOne(id);
    }

    /**
     * <p>根据课题组ID查询当前课题组下的所有启用的用户
     *
     * @param organizationId 课题组ID
     * @return List<SysUserMember> 用户列表
     */
    public List<SysUserMember> queryUserOfOrganization(String organizationId) {
        SysOrganization sysOrganization = sysOrganizationRepository.findOne(organizationId);
        if (sysOrganization == null){
            return Collections.emptyList();
        }
        List<SysOrganization> list = sysOrganizationRepository.getChildOrgByParentId(sysOrganization.getId());
        list.add(sysOrganization);
        Map<String, SysUserMember> memberMap = new HashMap<String, SysUserMember>();
        for (SysOrganization organization : list) {
            if (ValidatorUtils.isArrayNotEmpty(organization.getUserMembers())) {
                for (SysUserMember sysUserMember : organization.getUserMembers()) {
                    memberMap.put(sysUserMember.getId(), sysUserMember);
                }
            }
        }
        return new ArrayList<SysUserMember>(memberMap.values());
    }

    /**
     * 修改密码
     *
     * @param password 密码
     * @param id       主键
     * @return 布尔值 true:修改成功 false:修改失败
     */
    public boolean updateUserPassword(String password, String id) {
        SysUserMember us = sysUserRepository.findOne(id);
        SysUserSecurityType sysUserSecurityType = sysUserSecurityTypeService.getSysUserSecurityType();
        String passwordGenerate = "";
        if (sysUserSecurityType != null) {
            if (BaseConstant.MD5.equals(sysUserSecurityType.getSecurityType())) {//32
                passwordGenerate = AppUtils.GetMD5(password + us.getUserSalt(), 32, "MD5");
            } else if (BaseConstant.SHA_1.equals(sysUserSecurityType.getSecurityType())) {//40
                passwordGenerate = AppUtils.GetMD5(password + us.getUserSalt(), 32, "SHA-1");
            } else if (BaseConstant.SHA_256.equals(sysUserSecurityType.getSecurityType())) {//64
                passwordGenerate = AppUtils.GetMD5(password + us.getUserSalt(), 32, "SHA-256");
            }
        } else {
            passwordGenerate = AppUtils.GetMD5(password + us.getUserSalt(), 32, "MD5");
        }
        us.setUserPassword(passwordGenerate);
        sysUserRepository.save(us);
        return true;
    }

    /**
     * 验证用户输入密码和用户原密码是否相同
     *
     * @param password 密码
     * @return 布尔值 true:相同 false:不同
     */
    public boolean validatePasswordEqual(String password) {
        boolean flag = true;
        SysUserMember sum = sysUserRepository.findOne(AppUtils.getLoginUserId());
        try {
            String passwordGenerate = "";
            SysUserSecurityType sysUserSecurityType = sysUserSecurityTypeService.getSysUserSecurityType();
            if (sysUserSecurityType != null) {
                if (BaseConstant.MD5.equals(sysUserSecurityType.getSecurityType())) {//32
                    passwordGenerate = AppUtils.GetMD5(password + sum.getUserSalt(), 32, "MD5");
                } else if (BaseConstant.SHA_1.equals(sysUserSecurityType.getSecurityType())) {//40
                    passwordGenerate = AppUtils.GetMD5(password + sum.getUserSalt(), 32, "SHA-1");
                } else if (BaseConstant.SHA_256.equals(sysUserSecurityType.getSecurityType())) {//64
                    passwordGenerate = AppUtils.GetMD5(password + sum.getUserSalt(), 32, "SHA-256");
                }
            } else {
                passwordGenerate = AppUtils.GetMD5(password + sum.getUserSalt(), 32, "MD5");
            }
            if (!sum.getUserPassword().equals(passwordGenerate)) {
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }

    /**
     * 分页查询用户
     *
     * @param page
     * @param searchUserCondition
     * @return
     */
    public Page<SysUserMember> findAllByPage(Pageable page, final SearchUserCondition searchUserCondition) {
        if (searchUserCondition == null) {
            return sysUserRepository.findAll(page);
        }
        searchUserCondition.setLikeWord(true);
        Specification<SysUserMember> sysUserMemberSpecification = buildBaseSpecification(searchUserCondition);
        return findBySpe(sysUserMemberSpecification, page);
    }


    private Specification<SysUserMember> buildBaseSpecification(final SearchUserCondition searchUserCondition) {
        return SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {

            public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
                CriteriaQuery criteriaQuery = cb.createQuery();
                if (StringUtils.isNotBlank(searchUserCondition.getUserName())) {
                    list.add(
                            searchUserCondition.isLikeWord()
                                    ? cb.like(root.get("userName").as(String.class), "%" + searchUserCondition.getUserName() + "%")
                                    : cb.equal(root.get("userName").as(String.class), searchUserCondition.getUserName())
                    );
                }
                if (StringUtils.isNotBlank(searchUserCondition.getUserNumber())) {
                    list.add(
                            searchUserCondition.isLikeWord()
                                    ? cb.like(root.get("userNumber").as(String.class), "%" + searchUserCondition.getUserNumber() + "%")
                                    : cb.equal(root.get("userNumber").as(String.class), searchUserCondition.getUserNumber())
                    );
                }
                if (StringUtils.isNotBlank(searchUserCondition.getAlias())) {
                    list.add(searchUserCondition.isLikeWord()
                            ? cb.like(root.get("alias").as(String.class), "%" + searchUserCondition.getAlias() + "%")
                            : cb.equal(root.get("alias").as(String.class), searchUserCondition.getAlias()));
                }

                if (searchUserCondition.getAvailable() != null) {
                    list.add(cb.equal(root.get("available").as(Integer.class), searchUserCondition.getAvailable()));
                }
                if (StringUtils.isNotBlank(searchUserCondition.getOrgId())){
                    Subquery<SysUserMember> subquery = criteriaQuery.subquery(SysUserMember.class);
                    Root<SysOrganizationUser> fromProject = subquery.from(SysOrganizationUser.class);
                    subquery.select(fromProject.<SysUserMember>get("sysUserMember")); // field to map with main-query
                    SysOrganization organization = new SysOrganization();
                    organization.setId(searchUserCondition.getOrgId());
                    subquery.where(cb.equal(fromProject.get("sysOrganization"), organization));
                    CriteriaBuilder.In<SysUserMember> in = cb.in(root);
                    in.value(subquery);
                    list.add(in);
                }
                if (searchUserCondition.isButMe()){
                    list.add(cb.notEqual(root.get("id").as(String.class), AuthContextHelper.getLoginUser().getId()));
                }
                criteriaQuery.distinct(true);
            }
        });
    }

    /**
     * 查询用户
     *
     * @param searchUserCondition
     * @return
     */
    public List<SysUserMember> findAll(final SearchUserCondition searchUserCondition) {
        if (searchUserCondition == null) {
            return Collections.emptyList();
        }
        Specification<SysUserMember> specification = buildBaseSpecification(searchUserCondition);
        return findBySpe(specification, null).getContent();
    }

    private Page<SysUserMember> findBySpe(Specification<SysUserMember> specification, Pageable pageable) {
        if (specification == null) {
            return PageUtils.emptyPage(pageable);
        }
        return sysUserRepository.findAll(specification, pageable);
    }

    public List<SysUserMember> findAllByOrderNoASC(){
        Specification<SysUserMember> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {

            public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("available").as(Integer.class), BaseConstant.INTEGER_TRUE));
            }
        });
        return sysUserRepository.findAll(specification, new Sort(Sort.Direction.ASC, "orderNo"));
    }

    /**
     * 搜索用户
     *
     * @param ids
     * @return
     */
    public List<SysUserMember> findAll(Iterable<String> ids) {
        return sysUserRepository.findAll(ids);
    }

    /**
     * 根据登录名查询用户
     *
     * @param userNumber
     * @return
     */
    public SysUserMember doGetAuthenticationInfoByNumber(final String userNumber) {
        if (StringUtils.isBlank(userNumber)) {
            return null;
        }
        return sysUserRepository.findOne(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {
            public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("userNumber").as(String.class), userNumber));
            }
        }));
    }

    public SysUserMember findByIp(final String ipAddress) {
        if (StringUtils.isBlank(ipAddress)){
            return null;
        }
        return sysUserRepository.findOne(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysUserMember>() {

            public void fillParam(Root<SysUserMember> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.like(root.get("ipAddress").as(String.class), "%" + ipAddress + "%"));
            }
        }));
    }

    public List<SysUserMember> delUsers(final List<String> ids){
        List<TAttendance> attendances = attendanceDAO.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TAttendance>() {

            public void fillParam(Root<TAttendance> root, CriteriaBuilder cb, List<Predicate> list) {
                for (String id : ids) {
                    list.add(cb.or(
                            cb.equal(root.get("applyUser").get("id").as(String.class), id),
                            cb.equal(root.get("createUser").get("id").as(String.class), id)
                    ));
                }
            }
        }));
        attendanceDAO.delete(attendances);
        List<SysUserMember> users = sysUserRepository.findAll(ids);
        if (ValidatorUtils.isArrayNotEmpty(users)){
            for (SysUserMember user : users) {
                orgUserRepository.delete(user.getSysOrganizationUsers());
            }
        }
        sysUserRepository.delete(users);
        return users;
    }
}
